/*

    This file is part of Hometree.

    Hometree is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Hometree is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Hometree.  If not, see <http://www.gnu.org/licenses/>.

    Copyright 2011,2012 Roman Held

*/
#include <QDebug>
#include <QApplication>
#include <QDesktopWidget>
#include <QTimer>
#include <QWheelEvent>
#include <math.h>
#include "htrview.h"
#include "htrtreeentity.h"

// --------------------------------------------------------------------
#define  STEP_SIZE   2       // Width And Height Of Each Quad ( NEW )
bool  bRender=true;    // Polygon Flag Set To TRUE By Default ( NEW )

#define Height(m,x,y) qRed(m.pixel(x,y))

// --------------------------------------------------------------------
HtrView::HtrView()
 : QGLWidget()
{

  mMap = QImage(":/images/height_map.jpg");
  Q_ASSERT((mMap.height()*mMap.width()) > 0);

  mTreePos = QPointF(mMap.height()/2,mMap.width()/2);
  mCameraHeight = 5;
  mCameraRadius = 3;

  QTimer *t = new QTimer(this);
  connect(t, SIGNAL(timeout()), this, SLOT(updateGL()));
  t->start(70);

  mEntity = new HtrTreeEntity(this);
}


// --------------------------------------------------------------------
void HtrView::initializeGL()
{
  // Center
  move(QApplication::desktop()->width()/2 - width()/2,
       QApplication::desktop()->height()/2- height()/2);

  glEnable(GL_CULL_FACE);

  glEnable(GL_DEPTH_TEST);
  glEnable( GL_TEXTURE_2D );
  glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
 
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glEnable(GL_BLEND);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  //Perspektivische Darstellung
  gluPerspective(60.0,width()/height(),0.01,60);
  glMatrixMode(GL_MODELVIEW);


  // Nebel Einschalten:
  /*
  GLuint fogMode[]= { GL_EXP, GL_EXP2, GL_LINEAR }; // Storage For Three Types Of Fog
  GLuint fogfilter= 2; // Which Fog To Use

  GLfloat fogColor[4]= {0.7, 0.7, 1, 1.0}; // Fog Color

  // gray (air)
  glClearColor(0.7,0.7,0.7,1.0); // We'll Clear To The Color Of The Fog
  glClearColor(1,1,1,1); // We'll Clear To The Color Of The Fog

  glFogi(GL_FOG_MODE, fogMode[fogfilter]); // Fog Mode
  glFogfv(GL_FOG_COLOR, fogColor); // Set Fog Color
  glFogf(GL_FOG_DENSITY, 0.5); // How Dense Will The Fog Be
  glHint(GL_FOG_HINT, GL_DONT_CARE); // Fog Hint Value
  glFogf(GL_FOG_START, 5.0f); // Fog Start Depth
  glFogf(GL_FOG_END, 30.0); // Fog End Depth
  glEnable(GL_FOG); // Enables GL_FOG
  */
}

// --------------------------------------------------------------------
void HtrView::paintGL()
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glLoadIdentity();

  static float alpha = 0;
  alpha += 0.01;

  if (alpha > (2*3.1415))
    alpha=0;

  mCameraPos.setX(mTreePos.x() + sin(alpha)*mCameraRadius);
  mCameraPos.setY(mTreePos.y() + cos(alpha)*mCameraRadius);
 
  gluLookAt(   mCameraPos.x(),mCameraHeight,mCameraPos.y(), // von wo
               mTreePos.x(),0,mTreePos.y(),                 // nach wo
               0,1,0);                                      // Ausrichtung

  
  drawMap();
  drawTrees();
}

// --------------------------------------------------------------------
void HtrView::resizeGL(int width, int height)
{
  glViewport(0, 0, width, height);
}

// --------------------------------------------------------------------
void HtrView::mousePressEvent(QMouseEvent *event)
{
}

// --------------------------------------------------------------------
void HtrView::mouseReleaseEvent(QMouseEvent *event)
{
}

// --------------------------------------------------------------------
void HtrView::mouseMoveEvent(QMouseEvent *event)
{
}

// --------------------------------------------------------------------
void HtrView::keyPressEvent  ( QKeyEvent * event )
{
}

// --------------------------------------------------------------------
void HtrView::keyReleaseEvent( QKeyEvent * event )
{
}

// --------------------------------------------------------------------
void HtrView::wheelEvent(QWheelEvent * event )
{
  mCameraHeight *= event->delta() > 0 ? 1.1 : 0.9;
  mCameraRadius *= event->delta() > 0 ? 1.1 : 0.9;
}

// --------------------------------------------------------------------
void HtrView::drawMap()
{
  int X = 0, Y = 0;       // Create Some Variables To Walk The Array With.
  int x, y, z;            // Create Some Variables For Readability

  float xzScale = 0.6;
  float yScale  = 0.02;

  glPushMatrix();

  glScalef(xzScale, yScale, xzScale);

  if(bRender)             // What We Want To Render
    glBegin( GL_QUADS );  // Render Polygons
  else 
    glBegin( GL_LINES );  // Render Lines Instead

  glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
  for (X = 0; X < (mMap.width()-STEP_SIZE); X += STEP_SIZE ) {
    for ( Y = 0; Y < (mMap.height()-STEP_SIZE); Y += STEP_SIZE ) {
      if (((mTreePos.x()-X*xzScale)*(mTreePos.x()-X*xzScale) + (mTreePos.y()-Y*xzScale)*(mTreePos.y()-Y*xzScale)) > 30*30)
        continue;
      x = X;
      y = Height(mMap, X, Y );
      z = Y;
      glColor3f(0,0.1 + ((float)y)/256,0);
      glVertex3i(x, y, z);

      // Get The (X, Y, Z) Value For The Top Left Vertex
      x = X;
      y = Height(mMap, X, Y + STEP_SIZE ); 
      z = Y + STEP_SIZE ;
      glColor3f(0,0.1 + ((float)y)/256,0);
      glVertex3i(x, y, z);

      // Get The (X, Y, Z) Value For The Top Right Vertex
      x = X + STEP_SIZE; 
      y = Height(mMap, X + STEP_SIZE, Y + STEP_SIZE ); 
      z = Y + STEP_SIZE ;
      glColor3f(0,0.1 + ((float)y)/256,0);
      glVertex3i(x, y, z);


      x = X + STEP_SIZE; 
      y = Height(mMap, X + STEP_SIZE, Y ); 
      z = Y;
      glColor3f(0,0.1 + ((float)y)/256,0);
      glVertex3i(x, y, z);
    }
  }
  glEnd();
  glPopMatrix();
}


// --------------------------------------------------------------------
void HtrView::drawTrees()
{
  glPushMatrix();
  glTranslatef(mTreePos.x(), 1, mTreePos.y());
  mEntity->drawGL();
  glPopMatrix();
}

